package com.situ.shoplook.common.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.util.StringUtils;

import java.time.Duration;

/**
 * 功能：
 *
 * @author 千堆雪
 * @version 1.0.0
 * <p>
 * created by 千堆雪 on 2024/8/25, last modified by 千堆雪 on 2024/8/25
 */
@Configuration
public class SpringCacheConfig {

    /**
     * 自定义json序列化器
     *
     * @param mapper ObjectMapper实例
     * @return 自定义json序列化器
     */
    @Bean
    public RedisSerializer<Object> jackson2JsonRedisSerializer(ObjectMapper mapper) {
        ObjectMapper om = mapper.copy();//克隆一个新的ObjectMapper实例
        return GenericJackson2JsonRedisSerializer.builder().objectMapper(om).defaultTyping(true).build();
    }

    /**
     * 自定义RedisCacheManager是为了自定义序列化器。
     * 默认的CacheManager使用默认的JDK序列化器，序列化结果为二进制，无法序列化为json，不易读。
     * 且需要目标类必须实现Serializable接口（目标类的引用类型的属性也需要实现此接口）
     *
     * @return 自定义RedisCacheManager，可以序列化对象
     */
    @Bean
    public CacheManager redisCacheManager(RedisConnectionFactory connectionFactory, RedisSerializer<Object> valueSerializer) {
        RedisCacheWriter rcw = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory);

        RedisCacheConfiguration rcc = RedisCacheConfiguration.defaultCacheConfig()
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer))
                .entryTtl(Duration.ofHours(2));//设置缓存全局统一有效期，ttl表示time to live，即存活时间。
        return new RedisCacheManager(rcw, rcc);
    }

    /**
     * key生成器，包括方法名
     *
     * @return 包括方法的key生成器
     */
    @Bean
    public KeyGenerator customKeyGenerator() {
        return (target, method, params) -> {
            String key = method.getName();
            if (params.length > 0) {
                key += "_" + StringUtils.arrayToDelimitedString(params, "_");
            }
            return key;
        };
    }

}
